#include "EControllerQtProperty.h"
#include "DefineCommon.h"
#include "EItem.h"
#include "EItemManager.h"
#include "EItemMeta.h"
#include "EItemMetaFunction.h"
#include "EItemMetaProperty.h"
#include "EString.h"
#include "EVariant.h"
#include "WidgetVariant.h"
#include <WidgetVariantBool.h>
#include <WidgetVariantColor.h>
#include <WidgetVariantDouble.h>
#include <WidgetVariantInt.h>
#include <WidgetVariantMatrix.h>
#include <WidgetVariantString.h>
#include <WidgetVariantVec2.h>
#include <WidgetVariantVec3.h>
#include <WidgetVariantVec4.h>
#include <WidgetVariantButton.h>
#include "qobjectdefs.h"
#include "qtreewidget.h"
#include <ECommandManager.h>
#include <cstdint>



EControllerQtProperty::EControllerQtProperty()
{
    this->addCmdSenderList(this->getTag());
}

EControllerQtProperty::~EControllerQtProperty()
{
}

void EControllerQtProperty::setWidgetBox(WidgetBox* w)
{
    this->m_widgetBox = w;
}

void EControllerQtProperty::refresh()
{
}

bool EControllerQtProperty::handleEItem(EItemPtr item, int depth, EItemPtr parentItem)
{
    ELOG_DEBUG("selectedItem.name=%s", item->getName().data());

    this->m_itemPtr = item;
    this->m_mapTag2Property.clear();
    this->m_mapTag2WidgetVariant.clear();
    this->m_widgetBox->clear();

    EItemMetaPtr meta = item->getOrCreatMeta();
    meta->getClassName();
    meta->getClassDescription();

    for(size_t i =0 ; i < meta->getPropertyCount(); i++ )
    {
        EItemMetaPropertyPtr prop = meta->getProperty(i);
        QString groupName = prop->groupName.data();
        WidgetVariant* wPtr = this->convertPropertyToWidget(prop);
        if(wPtr != NULL)
        {
            this->m_widgetBox->addWidgetAndCategoryNew(wPtr, groupName);
            this->m_mapTag2WidgetVariant[prop->getTag()] = wPtr;
            this->m_mapTag2Property[prop->getTag()] = prop;
        }
    }

    for(size_t i =0 ; i < meta->getFunctionCount(); i++ )
    {
        EItemMetaFunctionPtr fun = meta->getFunction(i);
        fun->m_name;
        fun->getReturnProperty()->typeName;
    }

    this->m_widgetBox->installEventFilterForChildren();
    
    return true;
}

void EControllerQtProperty::handleCommand(const ECommandPtr& command)
{
    ELOG_DEBUG("cmd.name=%s", command->getName().data());
    if(command->getName() == "c:selectItem" 
            && command->getState() == ECommand::STATE::NORMAL
            && ifCmdSenderValid(command->getSender()))
    {
        EItemPtr selectedItem = command->getChild(0);
        this->handleEItem(selectedItem, -1, nullptr);
    }
    else if(command->getName() == "c:propertyChanged" 
            && command->getState() == ECommand::STATE::UNDO
            && ifCmdSenderValid(command->getSender()) )
    {
        EString propName = command->getOrCreatMeta()->getProperty("propName")->value.to_EString();
        long tagItem = command->getOrCreatMeta()->getProperty("tagItem")->value.to_intptr_t();
        long tagProperty = command->getOrCreatMeta()->getProperty("tagProperty")->value.to_intptr_t();
        EVariant oldValue = command->getOrCreatMeta()->getProperty("oldValue")->value;

        //if command's item is current item
        if(tagItem == this->m_itemPtr->getTag())
        {
            EItemMetaPropertyPtr p = this->m_itemPtr->getOrCreatMeta()->getProperty(propName);
            //set item's property value
            p->value = oldValue;
            //change Widget's value
            this->m_mapTag2WidgetVariant[tagProperty]->refreshByProperty(p);
        }
        else 
        {
        //if command's item is not current item
            EItemPtr item = EItemManager::instance()->getItemByTag(
                    EItemManager::instance()->getItemTreeRoot()
                    , tagItem
                    );
            if(item != nullptr)
            {
                EItemMetaPropertyPtr p = item->getOrCreatMeta()->getProperty(propName);
                //set item's property value
                p->value = oldValue;
            }
        }

        ELOG_DEBUG("UNDO cmd.name=%s \n propName=%s \noldValue=%s \nnewValue=%s"
                , command->getName().data()
                , propName.data()
                , command->getOrCreatMeta()->getProperty("oldValue")->value.getPrintStr().data()
                , command->getOrCreatMeta()->getProperty("newValue")->value.getPrintStr().data()
                );
    }
    else if(command->getName() == "c:propertyChanged" 
            && command->getState() == ECommand::STATE::REDO
            && ifCmdSenderValid(command->getSender()) )
    {
        EString propName = command->getOrCreatMeta()->getProperty("propName")->value.to_EString();
        long tagItem = command->getOrCreatMeta()->getProperty("tagItem")->value.to_intptr_t();
        long tagProperty = command->getOrCreatMeta()->getProperty("tagProperty")->value.to_intptr_t();
        EVariant newValue = command->getOrCreatMeta()->getProperty("newValue")->value;

        //if command's item is current item
        if(tagItem == this->m_itemPtr->getTag())
        {
            EItemMetaPropertyPtr p = this->m_itemPtr->getOrCreatMeta()->getProperty(propName);
            //set item's property value
            p->value = newValue;
            //change Widget's value
            this->m_mapTag2WidgetVariant[tagProperty]->refreshByProperty(p);
        }
        else 
        {
            //if command's item is not current item
            EItemPtr item = EItemManager::instance()->getItemByTag(
                    EItemManager::instance()->getItemTreeRoot()
                    , tagItem
                    );
            if(item != nullptr)
            {
                EItemMetaPropertyPtr p = item->getOrCreatMeta()->getProperty(propName);
                //set item's property value
                p->value = newValue;
            }
        }
        ELOG_DEBUG("REDO cmd.name=%s \n propName=%s \noldValue=%s \nnewValue=%s"
                , command->getName().data()
                , propName.data()
                , command->getOrCreatMeta()->getProperty("oldValue")->value.getPrintStr().data()
                , command->getOrCreatMeta()->getProperty("newValue")->value.getPrintStr().data()
                );
    }
}

WidgetVariant* EControllerQtProperty::convertPropertyToWidget(EItemMetaPropertyPtr p)
{
    WidgetVariant* wPtr = NULL;

    if(p->typeName == "int")
    {
        wPtr = new WidgetVariantInt;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "double")
    {
        wPtr = new WidgetVariantDouble;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "bool")
    {
        wPtr = new WidgetVariantBool;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "EVec3")
    {
        wPtr = new WidgetVariantVec3;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "EVec4")
    {
        wPtr = new WidgetVariantVec4;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "EMatrix4x4")
    {
        wPtr = new WidgetVariantMatrix;
        wPtr->refreshByProperty(p);
    }
    else if(p->typeName == "EString")
    {
        wPtr = new WidgetVariantString;
        wPtr->refreshByProperty(p);
    }

    if(wPtr != NULL)
    {
        QObject::connect(wPtr
                , SIGNAL(signalVariantChanged(EItemMetaPropertyPtr, EVariant ))
                , this
                , SLOT(slotVariantChanged(EItemMetaPropertyPtr, EVariant))
                );
    }

    return wPtr;
}

void EControllerQtProperty::slotVariantChanged(EItemMetaPropertyPtr p, EVariant oldValue )
{
    ECommandPtr newCmd = NewSmartPtr(ECommand)();
    newCmd->setSender( this->getTag() );
    newCmd->setName("c:propertyChanged");
    newCmd->getOrCreatMeta()->addProperty("newValue", p->value);
    newCmd->getOrCreatMeta()->addProperty("oldValue", oldValue);
    newCmd->getOrCreatMeta()->addProperty("tagProperty", EVariant(p->getTag()));
    newCmd->getOrCreatMeta()->addProperty("tagItem", EVariant(this->m_itemPtr->getTag()));
    newCmd->getOrCreatMeta()->addProperty("propName", p->name);
    ECommandManager::instance()->pushECommand(newCmd);

    // ELOG_DEBUG("property.name=%s", p->name.data());
}
